;  This file is part of tornado.
; 
;    tornado is free software: you can redistribute it And/Or modify
;    it under the terms of the GNU General Public License As published by
;    the Free Software Foundation, either version 3 of the License, Or
;    any later version.
; 
;    tornado is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY Or FITNESS For A PARTICULAR PURPOSE.  See the
;    GNU General Public License For more details.
; 
;    You should have received a copy of the GNU General Public License
;    along With tornado.  If Not, see <http://www.gnu.org/licenses/>. 2
; 

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL.i createGameServer(guid.s, gamePort.l, serverName.s, gameVersion.s, maxPlayer.l, password.s = "", console.b = #False)
  *s.sTornadoServer = new(sTornadoServer)
  InitializeStructure(*s,sTornadoServer)
  If *s
    
    InitNetwork()
    
    createLogFile(console)
    
    *s\mConnectionID = CreateNetworkServer(#PB_Any,gamePort,#PB_Network_UDP)
    If *s\mConnectionID
      *s\mGUID                  = guid
      *s\mName                  = serverName
      *s\mVersion               = gameVersion
      *s\mMaxPlayer             = maxPlayer
      *s\mPassword              = password
      *s\mLastConnectedSlot     = -1
      *s\mLastDisConnectedSlot  = -1
      *s\mEvent                 = #TORNADO_EVENT_NONE
      *s\mEventSlot             = -1
      
      ReDim *s\mClientSlot(maxPlayer-1)
      
      For i = 0 To maxPlayer-1
        *s\mClientSlot(i)\mClientID = #Null 
      Next 
      
      
      
      writeLog("Server created on port : "+Str(gamePort))
      writeLog("Server GUID : "+guid)
      writeLog("Server maximum player : "+Str(maxPlayer))
      writeLog("Server name : "+serverName)
      
      If *s\mPassword <> ""
        writeLog("Server is protected by password.")
      EndIf
      
      
      
      ProcedureReturn *s
    Else
      writeLog("Server failed to create on port : "+Str(gamePort)+ ", port in use ?")
      FreeMemory(*s)
      ProcedureReturn -1
    EndIf
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL gameServerRun(*s.sTornadoServer)
  If *s
 
    serverEvent = NetworkServerEvent()
    fromClient  = EventClient()
    
    ;
    ; Receive data
    ;
    If serverEvent = #PB_NetworkEvent_Data
      *packet.sPacket = receivePacket(fromClient)
      If *packet <> #Null 
        
        Select getPacketType(*packet)
            
          Case #PACKET_SYSTEM
            ;PrintN("Receive system packet from "+Str(fromClient))
            AddElement(*s\mSystemPacketReceived())
            
            *s\mSystemPacketReceived()\mData = AllocateMemory(#PACKET_LIMIT)
            CopyMemory(*packet\mData, *s\mSystemPacketReceived()\mData, #PACKET_LIMIT)
            *s\mSystemPacketReceived()\mOffset      = 2
            *s\mSystemPacketReceived()\mDestination = fromClient
            *s\mSystemPacketReceived()\mFromIP      = IPString(GetClientIP(fromClient))
            
            freePacket(*packet)
            
          Case #PACKET_CUSTOM
            ; PrintN("Receive custom packet from "+Str(fromClient))
            AddElement(*s\mCustomPacketReceived())
            
            *s\mCustomPacketReceived()\mData = AllocateMemory(#PACKET_LIMIT)
            CopyMemory(*packet\mData, *s\mCustomPacketReceived()\mData, #PACKET_LIMIT)
            *s\mCustomPacketReceived()\mOffset = 2
            *s\mCustomPacketReceived()\mDestination = fromClient
            *s\mCustomPacketReceived()\mFromIP      = IPString(GetClientIP(fromClient))
            
            freePacket(*packet)
            
            
        EndSelect
        
        
      Else
        ; not a valid packet
      EndIf 
      
    EndIf 
    
    ;
    ; compute system packet
    ;
    If ListSize(*s\mSystemPacketReceived()) > 0
      ForEach *s\mSystemPacketReceived()
        
        packetID.a = 0
        popPacket(*s\mSystemPacketReceived(),@packetID)
        ;PrintN("PacketID : "+Str(packetID))
        Select packetID
            ;
            ; client try to connect
            ;
          Case #CLIENT_TRY_TO_CONNECT
            
            pseudo$     = Space(512)
            password$   = Space(512)
            guid$       = Space(512)
            version$    = Space(512)
            gameName$   = Space(512)
            
            popPacket(*s\mSystemPacketReceived(),@pseudo$)
            popPacket(*s\mSystemPacketReceived(),@password$)
            popPacket(*s\mSystemPacketReceived(),@guid$)
            popPacket(*s\mSystemPacketReceived(),@version$)
            popPacket(*s\mSystemPacketReceived(),@gameName$)
            
            If gameName$ <> *s\mName
              *packet.sPacket      = createPacket(#PACKET_SYSTEM)
              *packet\mDestination = *s\mSystemPacketReceived()\mDestination
              
              value.a = #SERVER_SEND_BAD_GAMENAME
              pushPacket(*packet, @value,#TYPE_ASCII)
              serverAddPacket(*packet,*s)
              writeLog("Client "+pseudo$+" has bad guid")
            Else
            
            
            ; PrintN("Connection de "+pseudo$ + "  pn:"+Str(getPacketNumber(*s\mSystemPacketReceived())))
            
            writeLog("Client try to connect : "+pseudo$+" ("+IPString(GetClientIP(*s\mSystemPacketReceived()\mDestination))+")")
            
            If guid$ <> *s\mGUID
              ;
              ; bad guid
              ;
              *packet.sPacket      = createPacket(#PACKET_SYSTEM)
              *packet\mDestination = *s\mSystemPacketReceived()\mDestination
              
              value.a = #SERVER_SEND_BAD_GUID
              pushPacket(*packet, @value,#TYPE_ASCII)
              serverAddPacket(*packet,*s)
              writeLog("Client "+pseudo$+" has bad guid")
            Else
              
              If version$ <> *s\mVersion
                ;
                ; bad version
                ;
                *packet.sPacket      = createPacket(#PACKET_SYSTEM)
                *packet\mDestination = *s\mSystemPacketReceived()\mDestination
                
                value.a = #SERVER_SEND_BAD_VERSION
                pushPacket(*packet, @value,#TYPE_ASCII)
                serverAddPacket(*packet,*s)
                ;PrintN("bad version")
                writeLog("Client "+pseudo$+" has bad version")
              Else
                
                If password$ <> *s\mPassword
                  ;
                  ; bad password
                  ;
                  *packet.sPacket      = createPacket(#PACKET_SYSTEM)
                  *packet\mDestination = *s\mSystemPacketReceived()\mDestination
                  
                  value.a = #SERVER_SEND_BAD_PASSWORD
                  pushPacket(*packet, @value,#TYPE_ASCII)
                  serverAddPacket(*packet,*s)
                  ;PrintN("bad password")
                  writeLog("Client "+pseudo$+" has bad password")
                  
                Else 
                  
                  If FindMapElement(*s\mBannedIP(),*s\mSystemPacketReceived()\mFromIP)<>0
                    
                    ;
                    ; ban from ip
                    ;
                    *packet.sPacket      = createPacket(#PACKET_SYSTEM)
                    *packet\mDestination = *s\mSystemPacketReceived()\mDestination
                    ip.s     = *s\mSystemPacketReceived()\mFromIP
                    reason.s = *s\mBannedIP(ip)\mReason
                    time.l   = *s\mBannedIP(ip)\mTime
                    value.a  = #SERVER_SEND_BAN_BY_IP
                    pushPacket(*packet, @value,#TYPE_ASCII)
                    pushPacket(*packet, @reason,#TYPE_STRING)
                    pushPacket(*packet, @time,#TYPE_LONG)
                    
                    serverAddPacket(*packet,*s)
                    ;PrintN("ban by ip")
                    writeLog("Client "+pseudo$+" is banned from IP, reason : "+reason)
                  Else
                    
                    If FindMapElement(*s\mBannedPseudo(),pseudo$)<>0
                      
                      ;
                      ; ban from pseudo
                      ;
                      *packet.sPacket      = createPacket(#PACKET_SYSTEM)
                      *packet\mDestination = *s\mSystemPacketReceived()\mDestination
                      
                      reason.s = *s\mBannedPseudo(pseudo$)\mReason
                      time.l   = *s\mBannedPseudo(pseudo$)\mTime
                      value.a  = #SERVER_SEND_BAN_BY_PSEUDO
                      pushPacket(*packet, @value,#TYPE_ASCII)
                      pushPacket(*packet, @reason,#TYPE_STRING)
                      pushPacket(*packet, @time,#TYPE_LONG)
                      
                      serverAddPacket(*packet,*s)
                      ;PrintN("ban by pseudo")
                      writeLog("Client "+pseudo$+" is banned for illegal pseudo, reason : "+reason)
                    Else
                      ;
                      ; check server slot
                      ;
                      slot.l = -1
                      
                      ;
                      ; check for double
                      ;
                      For i = 0 To *s\mMaxPlayer - 1
                        If *s\mClientSlot(i)\mClientID  = *s\mSystemPacketReceived()\mDestination
                          slot = i
                        EndIf 
                      Next 
                      
                      ;
                      ; attribute new slot
                      ;
                      If slot = -1
                        For i = 0 To *s\mMaxPlayer - 1
                          If *s\mClientSlot(i)\mClientID = 0
                            slot = i
                            *s\mClientSlot(i)\mClientID      = *s\mSystemPacketReceived()\mDestination
                            *s\mClientSlot(i)\mAliveTimer    = ElapsedMilliseconds() + 5000
                            *s\mClientSlot(i)\mClientPseudo  = pseudo$
                            *s\mClientSlot(i)\mIsActive      = #True 
                            *s\mNbPlayer + 1
                            Break
                          EndIf 
                        Next
                      EndIf 
                      ;
                      ; server is full
                      ;
                      If slot = -1
                        *packet.sPacket      = createPacket(#PACKET_SYSTEM)
                        *packet\mDestination = *s\mSystemPacketReceived()\mDestination
                        
                        value.a = #SERVER_SEND_FULL
                        pushPacket(*packet, @value,#TYPE_ASCII)
                        serverAddPacket(*packet,*s)
                        ;PrintN("server is full")
                        writeLog("Client "+pseudo$+" can't join, server is full")
                      Else
                        ;
                        ; send slot
                        ;
                        *packet.sPacket      = createPacket(#PACKET_SYSTEM)
                        *packet\mDestination = *s\mSystemPacketReceived()\mDestination
                        
                        value.a = #SERVER_SEND_SLOT
                        pushPacket(*packet, @value,#TYPE_ASCII)
                        pushPacket(*packet, @slot,#TYPE_LONG)
                        serverAddPacket(*packet,*s)
                        
                        ;PrintN("send slot number for client : " + *s\mSystemPacketReceived()\mDestination + " = " +Str(slot) )
                        
                        writeLog("Client "+pseudo$+" joining server.")
                        
                        *s\mEvent       = #TORNADO_EVENT_PLAYER_CONNECTED
                        *s\mEventSlot   = slot
                        
                        ;
                        ; advise other client
                        ;
                        
                        *packet.sPacket      = createPacket(#PACKET_SYSTEM)
                        *packet\mDestination = -1 ; to all
                        value.a = #SERVER_SEND_UPDATE_LIST
                        pushPacket(*packet, @value,#TYPE_ASCII)
                        
                        For i = 0 To *s\mMaxPlayer - 1
                          pushPacket(*packet, @i,#TYPE_ASCII)
                          pushPacket(*packet, @*s\mClientSlot(i)\mClientPseudo,#TYPE_STRING)
                          pushPacket(*packet, @*s\mClientSlot(i)\mIsActive,#TYPE_BYTE)
                        Next
                        
                        
                        serverAddPacket(*packet,*s)
                        
                        
                        ;
                        ; send who is connected
                        ;
                        
                        *s\mLastConnectedSlot = slot
                        *s\mClientUpdate = #True 
                        *packet2.sPacket = createPacket(#PACKET_SYSTEM)
                        *packet2\mDestination = -1
                        value = #SERVER_SEND_PLAYER_CONNECTED
                        pushPacket(*packet2, @value,#TYPE_ASCII)
                        pushPacket(*packet2, @slot,#TYPE_LONG)
                        
                        serverAddPacket(*packet2,*s)
                        
                      EndIf 
                      
                    EndIf
                  EndIf 
                EndIf 
              EndIf 
            EndIf ; // guid test
          EndIf 
          
          Case #CLIENT_REQUEST_INFO
            
            guid$       = Space(512)
            popPacket(*s\mSystemPacketReceived(),@guid$)
            
            If guid$ = *s\mGUID
              *packet.sPacket      = createPacket(#PACKET_SYSTEM)
              *packet\mDestination = *s\mSystemPacketReceived()\mDestination
              
              value.a = #SERVER_SEND_INFORMATION
              pushPacket(*packet, @value,#TYPE_ASCII)
              pushPacket(*packet, @*s\mNbPlayer,#TYPE_LONG)
              pushPacket(*packet, @*s\mMaxPlayer,#TYPE_LONG)
              
              
              If *s\mPassword <> ""
                value = 1
                pushPacket(*packet, @value,#TYPE_ASCII)
              Else
                value = 0
                pushPacket(*packet, @value,#TYPE_ASCII)
              EndIf
              
              pushPacket(*packet, @*s\mName,#TYPE_STRING)
              pushPacket(*packet, @*s\mVersion,#TYPE_STRING)
                          
              serverAddPacket(*packet,*s)
              
              writeLog("Server send request information at "+IPString(GetClientIP(*packet\mDestination)))
            Else
              ;
              ; bad guid
              ;
              *packet.sPacket      = createPacket(#PACKET_SYSTEM)
              *packet\mDestination = *s\mSystemPacketReceived()\mDestination
              
              value.a = #SERVER_SEND_BAD_GUID
              pushPacket(*packet, @value,#TYPE_ASCII)
              serverAddPacket(*packet,*s)
              
            EndIf 
          Case #CLIENT_SEND_ALIVE_SIGNAL
            slotNumber.l 
            popPacket(*s\mSystemPacketReceived(), @slotNumber)
            
            If *s\mClientSlot(i)\mClientID<>0
              *s\mClientSlot( slotNumber)\mAliveTimer = ElapsedMilliseconds() + 5000
            EndIf

            
          Case #CLIENT_SEND_PONG
            
            
            fromSlot.l
            popPacket(*s\mSystemPacketReceived(),@fromSlot)
            
            *s\mClientSlot(fromSlot)\mPongMarker = ElapsedMilliseconds()
            *s\mClientSlot(fromSlot)\mPing       = (*s\mClientSlot(fromSlot)\mPongMarker - *s\mClientSlot(fromSlot)\mPingMarker)/2
            
            
          Case #CLIENT_SEND_GIVE_MY_PING

            forSlot.l
            popPacket(*s\mSystemPacketReceived(),@forSlot)
            *packet.sPacket      = createPacket(#PACKET_SYSTEM)
            *packet\mDestination = *s\mSystemPacketReceived()\mDestination
            header.a = #SERVER_SEND_PING_FOR_SLOT
            pushPacket(*packet,@header,#TYPE_ASCII)
            pushPacket(*packet, @forSlot,#TYPE_LONG)
            pushPacket(*packet, @*s\mClientSlot(forSlot)\mPing,#TYPE_LONG)
            serverAddPacket(*packet,*s)
            
          Case #CLIENT_SEND_DISCONNECT
            
            slot.l
            popPacket(*s\mSystemPacketReceived(),@slot)
            *s\mClientSlot(slot)\mClientID = 0
            *s\mClientSlot(slot)\mIsActive = #False 
            
            writeLog("Client "+*s\mClientSlot(slot)\mClientPseudo+" has left server.")
            
            *s\mEvent       = #TORNADO_EVENT_PLAYER_DISCONNECTED
            *s\mEventSlot   = fromSlot
            *s\mNbPlayer    - 1
            
            ;
            ; advise other client
            ;
            
            *packet.sPacket      = createPacket(#PACKET_SYSTEM)
            *packet\mDestination = -1 ; to all
            value.a = #SERVER_SEND_UPDATE_LIST
            pushPacket(*packet, @value,#TYPE_ASCII)
            
            For i = 0 To *s\mMaxPlayer - 1
              pushPacket(*packet, @i,#TYPE_ASCII)
              pushPacket(*packet, @*s\mClientSlot(i)\mClientPseudo,#TYPE_STRING)
              pushPacket(*packet, @*s\mClientSlot(i)\mIsActive,#TYPE_BYTE)
            Next
            
            
            serverAddPacket(*packet,*s)
            ;
            ; send who is disconnected
            ;
            
            *s\mLastDisConnectedSlot = slot
            *s\mClientUpdate = #True 
            *packet2.sPacket = createPacket(#PACKET_SYSTEM)
            *packet2\mDestination = -1
            value = #SERVER_SEND_PLAYER_DISCONNECTED
            pushPacket(*packet2, @value,#TYPE_ASCII)
            pushPacket(*packet2, @slot,#TYPE_LONG)
            
            serverAddPacket(*packet2,*s)
            
          Case #CLIENT_SEND_CHANGE_NICKNAME
            
            fromSlot.l
            nickName.s = Space(512)

            popPacket(*s\mSystemPacketReceived(),@fromSlot)
            popPacket(*s\mSystemPacketReceived(),@nickName)
            
            writeLog("Player "+*s\mClientSlot(fromSlot)\mClientPseudo+ " change to "+nickName)            
            
            *s\mClientSlot(fromSlot)\mClientPseudo = nickName
            
            *packet.sPacket = createPacket(#PACKET_SYSTEM)
            *packet\mDestination = -1
            value = #SERVER_SEND_PLAYER_CHANGE_NICKNAME
            pushPacket(*packet, @value,#TYPE_ASCII)
            pushPacket(*packet, @fromSlot,#TYPE_LONG)
            pushPacket(*packet, @nickName,#TYPE_STRING)
            
            serverAddPacket(*packet,*s)
            
            *s\mEvent       = #TORNADO_EVENT_PLAYER_CHANGE_NICKNAME
            *s\mEventSlot   = fromSlot
            
            
            
        EndSelect
        
        
        FreeMemory(*s\mSystemPacketReceived()\mData)
        DeleteElement(*s\mSystemPacketReceived())
      Next 
    EndIf 
    
    
    ;
    ; send system packets
    ;
    If *s\mPacketManager\mSystemTimer < ElapsedMilliseconds()
      *s\mPacketManager\mSystemTimer  = ElapsedMilliseconds() + 100
      
      ForEach *s\mPacketManager\mSystemPacket()
        
        destination.i = *s\mPacketManager\mSystemPacket()\mDestination
        
        If destination <> -1
          SendNetworkData(destination,*s\mPacketManager\mSystemPacket()\mData,#PACKET_LIMIT)
        Else
          For i = 0 To *s\mMaxPlayer - 1
            If *s\mClientSlot(i)\mClientID <> 0
              SendNetworkData(*s\mClientSlot(i)\mClientID,*s\mPacketManager\mSystemPacket()\mData,#PACKET_LIMIT)
            EndIf 
          Next
        EndIf 
        
        FreeMemory(*s\mPacketManager\mSystemPacket()\mData)
        DeleteElement(*s\mPacketManager\mSystemPacket())
        
        
      Next 
      
    EndIf 
    
    
    ;
    ; send custom packets
    ;
    If *s\mPacketManager\mCustomTimer < ElapsedMilliseconds()
      *s\mPacketManager\mCustomTimer  = ElapsedMilliseconds() + 30
      
      ForEach *s\mPacketManager\mCustomPacket()
        destination.i = *s\mPacketManager\mCustomPacket()\mDestination
        If destination <> -1
            SendNetworkData(destination,*s\mPacketManager\mCustomPacket()\mData,#PACKET_LIMIT)
        Else
          For i = 0 To *s\mMaxPlayer - 1
            If *s\mClientSlot(i)\mClientID <> 0
              SendNetworkData(*s\mClientSlot(i)\mClientID,*s\mPacketManager\mCustomPacket()\mData,#PACKET_LIMIT)
            EndIf 
          Next
        EndIf 
        
        FreeMemory(*s\mPacketManager\mCustomPacket()\mData)
        DeleteElement(*s\mPacketManager\mCustomPacket())

      Next 
      
    EndIf 
    
    
    ;
    ; check temporary banned list for unban based on time
    ;
    If *s\mUnBanTimer < ElapsedMilliseconds()
      *s\mUnBanTimer = ElapsedMilliseconds() + 1000
      
      ForEach *s\mBannedIP()
        If *s\mBannedIP()\mTime<>-1
          *s\mBannedIP()\mTime - 1
          If *s\mBannedIP()\mTime = 0
            DeleteMapElement(*s\mBannedIP(), MapKey(*s\mBannedIP()))
            Continue
          EndIf 
        EndIf 
      Next
      
      ForEach *s\mBannedPseudo()
        If *s\mBannedPseudo()\mTime<>-1
          *s\mBannedPseudo()\mTime - 1
          If *s\mBannedPseudo()\mTime = 0
            DeleteMapElement(*s\mBannedPseudo(), MapKey(*s\mBannedPseudo()))
            Continue
          EndIf 
        EndIf
      Next
      
    EndIf 
    
    
    ;
    ; check for alive signal
    ;
    For i = 0 To *s\mMaxPlayer-1
      ;
      ; client is dead
      ;
      If *s\mClientSlot(i)\mClientID <> 0
        If *s\mClientSlot(i)\mAliveTimer < ElapsedMilliseconds()
          *s\mClientSlot(i)\mClientID   = 0
          *s\mClientSlot(i)\mAliveTimer = 0
          *s\mClientSlot(i)\mIsActive   = #False
          *s\mNbPlayer - 1
          
          *s\mEvent       = #TORNADO_EVENT_LOOSE_CONNECTION
          *s\mEventSlot   = i
          
          ;
          ; advise other client
          ;
          *packet.sPacket      = createPacket(#PACKET_SYSTEM)
          *packet\mDestination = -1 ; to all
          
          value.a = #SERVER_SEND_UPDATE_LIST
          pushPacket(*packet, @value,#TYPE_ASCII)
          
          For j = 0 To *s\mMaxPlayer - 1
            pushPacket(*packet, @j,#TYPE_ASCII)
            pushPacket(*packet, @*s\mClientSlot(j)\mClientPseudo,#TYPE_STRING)
            pushPacket(*packet, @*s\mClientSlot(j)\mIsActive,#TYPE_BYTE)
          Next

          serverAddPacket(*packet,*s)
          
          ;
          ; send who is disconnected
          ;
          writeLog("Player " + *s\mClientSlot(i)\mClientPseudo + " loose connection.")
          *s\mLastDisConnectedSlot = i
          *s\mClientUpdate         = #True 
          
          *packet2.sPacket = createPacket(#PACKET_SYSTEM)
          *packet2\mDestination = -1
          value = #SERVER_SEND_PLAYER_DISCONNECTED
          pushPacket(*packet2, @value,#TYPE_ASCII)
          pushPacket(*packet2, @i,#TYPE_LONG)
          
          serverAddPacket(*packet2,*s)
          
          
        EndIf 
      EndIf
    Next 
    
    
    ;
    ; send ping
    ;
    If *s\mPingTimer < ElapsedMilliseconds()
      *s\mPingTimer = ElapsedMilliseconds() + 1000
      
      *packet.sPacket      = createPacket(#PACKET_SYSTEM)
      *packet\mDestination = -1 ; to all
      value.a = #SERVER_SEND_PING
      pushPacket(*packet, @value,#TYPE_ASCII)
          
      For i = 0 To *s\mMaxPlayer - 1
        If *s\mClientSlot(i)\mClientID <> 0
          *s\mClientSlot(i)\mPingMarker = ElapsedMilliseconds()
          If *s\mClientSlot(i)\mClientID <> #Null 
            SendNetworkData(*s\mClientSlot(i)\mClientID,*packet\mData,#PACKET_LIMIT)
          EndIf 
        EndIf
      Next
      
      freePacket(*packet)
    EndIf 
    

  EndIf
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL.l serverGetLastConnected(*s.sTornadoServer)
  If *s
    result.l = *s\mLastConnectedSlot
    *s\mLastConnectedSlot = -1
    ProcedureReturn result
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverGetLastDisConnected(*s.sTornadoServer)
  If *s
    result = *s\mLastDisConnectedSlot
    *s\mLastDisConnectedSlot = -1 
    ProcedureReturn result
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverSetPacketDestination(*s.sTornadoServer, *p.sPacket, slot.l)
  If *s
    If *p
      If slot <> -1
        *p\mDestination = *s\mClientSlot(slot)\mClientID
      Else
        *p\mDestination = -1
      EndIf 
    EndIf
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverGetClientNickname(*s.sTornadoServer, slot.l , *string)
  If *s
    result$ = *s\mClientSlot(slot)\mClientPseudo
    PokeS(*string,result$)
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL.l serverEvent(*s.sTornadoServer)
  If *s
    result.l = *s\mEvent
    *s\mEvent = #TORNADO_EVENT_NONE
    ProcedureReturn result
  EndIf
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL.l serverEventSlot(*s.sTornadoServer)
  If *s
    result.l = *s\mEventSlot
    *s\mEventSlot = -1
    ProcedureReturn result
  EndIf
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverDisconnect(*s.sTornadoServer)
  If *s
    CloseNetworkServer(*s\mConnectionID)
    FreeList(*s\mCustomPacketReceived())
    FreeList(*s\mSystemPacketReceived())
    FreeArray(*s\mClientSlot())
    FreeMap(*s\mBannedIP())
    FreeMap(*s\mBannedPseudo())
    FreeMap(*s\mCmd())
  EndIf 
EndProcedure 

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverKickPlayer(*s.sTornadoServer, slot.l, reason.s)
  If *s
     
      
      
      ;
      ; kick player
      ;
      *packetForBanned.sPacket      = createPacket(#PACKET_SYSTEM)
      *packetForBanned\mDestination = slot
      value.a = #SERVER_SEND_KICK
      pushPacket(*packetForBanned, @value,#TYPE_ASCII)
      pushPacket(*packetForBanned, @reason,#TYPE_STRING)
      
      serverAddPacket(*packetForBanned,*s)
      
      ;
      ; advise other player
      ;
      *packet.sPacket      = createPacket(#PACKET_SYSTEM)
      *packet\mDestination = -1
      value.a = #SERVER_SEND_PLAYER_HAS_BEEN_KICKED
      pushPacket(*packet, @value,#TYPE_ASCII)
      pushPacket(*packet, @slot,#TYPE_LONG)
      pushPacket(*packet, @reason,#TYPE_STRING)
      
      serverAddPacket(*packetForBanned,*s)
      
      
      
      
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverAddBannedIp(*s.sTornadoServer,ip$, time.i, reason.s)
  If *s
    *s\mBannedIP(ip$)\mTime   = time
    *s\mBannedIP(ip$)\mReason = reason
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverAddBannedNickname(*s.sTornadoServer,pseudo$, time.i, reason.s)
  If *s
    *s\mBannedPseudo(pseudo$)\mTime   = time
    *s\mBannedPseudo(pseudo$)\mReason = reason
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverSetAdminPassword(*s.sTornadoServer, password.s)
  If *s
    *s\mAdminPassword = password
  EndIf 
EndProcedure

; /////////////////////////////////////////////////////////////////////////////
;
; /////////////////////////////////////////////////////////////////////////////
ProcedureDLL serverCreateCmd(*s.sTornadoServer, cmd.s, *func)
  If *s
    *s\mCmd(cmd) = *func
  EndIf 
EndProcedure
